package com.cshuig.singleton;

/**
 * Created by cshuig on 15/6/22.
 * 线程安全双重检查加锁的单例初始化
 * <p>
 * 双重检查加锁：指并不是每次进入  getInstance方法都需要同步, 而是先不同步, 当进入方法后先检查实例是否存在, 如果不存在才需要进入同步块, 当进入同步块后再次检查实例是否存在
 * 在使用"双重检查加锁"机制时候, 需要使用关键字, volatile， 含义是被volatile修饰的变量值不会被本地线程缓存, 所有对该变量的读写都是直接操作共享内存, 从而确保多个线程能正确地处理该变量.
 */
public class ThreadSafeDoubleCheckedLockingLazyLoader {

    private static volatile ThreadSafeDoubleCheckedLockingLazyLoader threadSafeDoubleCheckedLockingLazyLoader = null;

    private ThreadSafeDoubleCheckedLockingLazyLoader() {
        System.out.println("ThreadSafeDoubleCheckedLockingLazyLoader init");
    }

    /**
     * 这种方式不但可以实现线程安全地创建实例, 而且又不会对性能造成太大的影响, 它只是第一次创建实例的时候同步, 以后就不需要同步了, 从而加快运行速度。
     * 因为volatile关键字可能会屏蔽掉虚拟机中的一下必需优化代码, 所有允许效率并不是很高.
     * 所以建议：如果没有特别的需要, 不要使用volatile关键字, 也就是说 "双重检查加锁"不建议大量采用.
     * @return
     */
    public static ThreadSafeDoubleCheckedLockingLazyLoader getInstance() {
        if (threadSafeDoubleCheckedLockingLazyLoader == null) {
            synchronized (ThreadSafeDoubleCheckedLockingLazyLoader.class) {
                if (threadSafeDoubleCheckedLockingLazyLoader == null) {
                    threadSafeDoubleCheckedLockingLazyLoader = new ThreadSafeDoubleCheckedLockingLazyLoader();
                }
            }
        }
        return threadSafeDoubleCheckedLockingLazyLoader;
    }

}
